using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;

// TT Nov-2007 - To insert a delay
// This is NOT a good way to do it!
using System.Threading;


namespace ProMRDS.Robotics.Lynxmotion.Ssc32
{
    internal class SSC32Comm
    {
        private SerialPort _sPort;

        public SSC32Comm()
        {
            // Open the port with default settings
            SerialPortConfig config = new SerialPortConfig();
            InitPort(config);
        }

        ~SSC32Comm()
        {
            ClosePort();
        }

        //Sends command to controller board
        //returns true if the command is successful, false otherwise
        internal bool StreamCommand(string command)
        {
            try
            {
                _sPort.Write(command);
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        //Sends command to controller board and reads a byte array of responseSize
        //returns byte[] if the command is successful, null otherwise
        internal byte[] StreamQuery(string query, int responseSize)
        {
            int bytesRead = 0;
            byte[] result = new byte[responseSize];
            try
            {
                // TT - Make sure the input buffer is empty before we start reading
                // There was a strange problem where the values would continually
                // move from one channel to another probably due to extraneous data
                // in the buffer
                _sPort.DiscardInBuffer();

                // Send the query
                _sPort.Write(query);

                //attempt to get responseSize number of bytes
                for (int attempt = 0; attempt < 20 && bytesRead < responseSize; attempt++)
                {
                    if (_sPort.BytesToRead > 0)
                    {
                        bytesRead += _sPort.Read(result, bytesRead, responseSize - bytesRead);
                    }
                    // TT - This might be spinning around the loop too fast,
                    // although this is unlikely given the timeout that is set.
                    // Added a sleep to slow it down.
                    Thread.Sleep(5);
                }

                if (bytesRead < responseSize)
                    return null;
                else
                    return result;
            }
            catch (Exception)
            {
                return null;
            }            
        }

        internal void InitPort(SerialPortConfig config)
        {
            // Dispose of the old port if necessary
            ClosePort();

            // Create a new port and set its properties
            try
            {
                // Beyond the Port Name and Baud Rate settings, use the defaults for the port
                _sPort = new SerialPort();
                _sPort.PortName = config.PortName;
                _sPort.BaudRate = config.BaudRate;
                _sPort.WriteTimeout = config.QueryTimeOut;
                _sPort.ReadTimeout = config.QueryTimeOut;
                // Leave the other properties as default - this is what SSC32 expects
                _sPort.Open();
            }
            catch (Exception)
            {
                //Console.Error.WriteLine("Unable to open a new serial port connection");
                //Console.Error.WriteLine(ex.Message);
            }
        }

        internal void ClosePort()
        {
            if (_sPort == null)
                return;

            try
            {
                _sPort.Close();
                _sPort.Dispose();
            }
            catch (Exception)
            {
                //Console.Error.WriteLine("Could not dispose of existing comm port");
            }
        }
    }
}
